home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Libris Britannia 4
/
science library(b).zip
/
science library(b)
/
DDJMAG
/
DDJ9207.ZIP
/
ACOMP.ZIP
/
AC.ASM
next >
Wrap
Assembly Source File
|
1992-04-12
|
13KB
|
516 lines
;; AC.ASM -> ACOMP assembly language compressor. Written
;; by John W. Ratcliff, 1992. Uses Turbo Assembler
;; IDEAL mode and makes HEAVY use of macros. This
;; algorithm performs an exhaustive search for the
;; best delta mod for each section of the waveform.
;; It is very CPU intensive, and the algorithm can
;; be a little difficult to follow in assembly
;; language.
;;
;; You could develop a faster version of this algorithm by changing some of
;; the rules regarding how to find the best matching delta modulation values.
;; Also, when a RESYNC occurs you might continue to assume resyncing for an
;; entire frame. Another optimization would involve changing the allowable
;; error thershold relative the frequency response of the data at any given
;; time. Note that many changes and improvements may be made to the
;; compression algorithm without causing changes in the ACOMP file format.
;;
;; It might be interesting to note that ACOMP is successful at compressing
;; A/D converted data other than simply digital audio. Using ACOMP on a
;; black and white gray scale image achieved better than 4:1 compression with
;; very little loss of visual detail.
IDEAL ; Enter Turbo Assembler's IDEAL mode.
JUMPS ; Allow automatic jump sizing.
INCLUDE "prologue.mac" ; Include usefull assembly lanugage macro file.
SEGMENT _TEXT BYTE PUBLIC 'CODE'
ASSUME CS:_TEXT
;; This macro computes the amount of error in a frame of data, at this
;; bit resolution and this delta mod location.
Macro DoError BITS
LOCAL @@NO
mov bx,[COMP] ; Current delta mod value.
mov bh,BITS ; Current bit resolution.
push [MINERR] ; Pass minimum error so far.
push [PREV] ; Pass previous data point.
call ComputeError ; Compute error for frame.
add sp,4 ; Balance stack.
cmp dx,[MINERR] ; Less than previous minimum?
jge @@NO ; no, don't update.
mov [MINERR],dx ; Save as new miniume
mov [BESTPREV],ax ; Best previous location.
xor ah,ah ;
mov al,bl ; Get best delta modution.
mov [BEST1],ax ; save it.
mov al,bh ; Get best bits.
mov [BEST2],ax ; Save it.
@@NO:
endm
SQLCH equ 64 ; Squelch bit.
RESYNC equ 128 ; Resynchronization bit.
DELTAMOD equ 00110000b ; Bit mask for delta mod bits.
ONEBIT equ 00010000b ; Bit pattern for one bit delta mod.
TWOBIT equ 00100000b ; Bit pattern for two bit delta mod.
FOURBIT equ 00110000b ; Bit pattern for two bit delta mod.
;; This macro echos a message to the text screen, so that we can
;; monitor the progress of the compression algorithm.
Macro Note MSG
push ax
lea ax,[MSG]
push ax
call Notify
add sp,2
pop ax
endm
public _CompressAudio
;; This the the ACOMP compression procedure.
;;int far CompressAudio(unsigned char far *shand, Address of audio data to compress.
;; unsigned char far *dhand, Destination address of compressed data.
;; unsigned int slen, Length of audio data to compress.
;; int squelch, Squelch value allowed.
;; int freq, Playback frequency of audio data.
;; int frame, Frame size.
;; int maxerr); Maximum error allowed.
Proc _CompressAudio far
ARG SHAN:DWORD,DHAN:DWORD,SLEN:WORD,SQUELCH:WORD,FREQ:WORD,FRAME:WORD,MAXERR:WORD
LOCAL PREV:WORD,COMP:WORD,MINERR:WORD,BEST1:WORD,BEST2:WORD,BESTPREV:WORD = LocalSpace
PENTER LocalSpace
PushCREGS
lds si,[SHAN] ; Get source address.
les di,[DHAN] ; Get destination address.
mov cx,[SLEN] ; Get length of audio data.
mov ax,cx ; Get length of audio sample into AX
stosw ; Store it.
mov ax,[FREQ] ; Get frequency of recording.
stosw ; Store it.
mov ax,[FRAME] ; Get the frame size.
stosb ; Store it.
mov ax,[SQUELCH] ; Get squelch size
stosb ; Store it.
mov ax,[MAXERR] ; Get maximum error allowed.
stosw ; Save it.
xor ax,ax
lodsb ; Get first data sample
mov [PREV],ax
stosb ; Store first data sample.
dec cx ; Decrement sample size count.
jz @@DONE
@@SQU: mov ah,0Bh ; Test keyboard status.
int 21h
or al,al
jz @@NOK
mov ah,08h ; If a key was pressed get that key
int 21h ; value, and see if it was the
cmp al,27 ; escape key.
jne @@NOK
xor ax,ax ; If escape, return to caller, with abort.
jmp @@EXIT
@@NOK:
xor ax,ax
mov dx,[SQUELCH] ; Get squelch value.
push cx ; Save remaining data count.
push si ; Save si.
@@CK1: lodsb ; Get data byte.
sub ax,[PREV] ; Difference from previous data sample?
jns @@CK2 ; if positive leave it alone.
neg ax ; Make it positive.
@@CK2: cmp ax,dx ; Is it within the squelch range?
jg @@NOS ; yes, keep checking!
loop @@CK1 ; Keep going.
inc si ; Plus one, this last one counts.
@@NOS: pop ax ; Get back start SI
mov dx,si ; DX contains current address.
sub dx,ax ; Compute number of squelch bytes encountered.
dec dx ; Less, last non squelch byte.
cmp dx,3 ; At least three?
jle @@NOSQ ; no, don't squelch it.
@@SQS: cmp dx,63 ; Is it under 63?
jle @@SEND
mov ax,(63 + SQLCH) ; Send count.
sub dx,63 ; Less the 63 count we just sent.
stosb ; Write squelch byte out.
jmp short @@SQS ; Continue.
@@SEND: mov ax,dx ; Get remaining count.
or ax,SQLCH ; Or squelch bit on.
stosb ; Send squelch count out.
dec si ; Back up to last data point.
pop ax ; Pull CX off of stack, use current count.
Note msg0
jmp short @@NXT
@@NOSQ: mov si,ax ; Replace where source was.
pop cx ; Get back remaining data count.
@@NXT: jcxz @@DONE ; Exit if done.
cmp cx,[FRAME] ; Below current frame size?
jae @@GO ; no, go ahead.
@@FIN: lodsb ; Get raw sample.
shr al,1 ; Down to closest aproximated value.
or al,RESYNC ; Add resync bit to it.
stosb ; Store out.
loop @@FIN ; Keep sending final bytes.
jmp @@DONE ; exit, after sending final bytes.
@@GO: mov [MINERR],07FFFh
push cx
mov cx,[FRAME] ; Set CX to frame size.
mov [COMP],1
@@ALL1: DoError 1 ; Try one bit mode, +/-1.
inc [COMP]
cmp [COMP],17 ; Try delta comp values clean up to 16!!
jne @@ALL1
mov ax,[MINERR]
cmp ax,[MAXERR]
jle @@BCMP ; Not good enough...
mov [COMP],1
@@ALL2: DoError 2 ; Try two bit mode, +/-1.
inc [COMP]
cmp [COMP],17 ; Try delta comp values clean up to 16!!
jne @@ALL2
mov ax,[MINERR]
cmp ax,[MAXERR]
jle @@BCMP
mov [COMP],1
@@ALL4: DoError 8 ; Try four bit mode, +/-1.
inc [COMP]
cmp [COMP],17 ; Try delta comp values clean up to 16!!
jne @@ALL4
mov ax,[MINERR] ; Get what the minimum error was.
cmp ax,[MAXERR] ; Minimum error > maximum error?
jle @@BCMP ; no, then send frame.
pop cx ; Get back CX
lodsb ; Get data sample.
and al,(NOT 1) ; Strip off bottom bit.
xor ah,ah
mov [PREV],ax ; New previous.
shr al,1 ; /2
or al,RESYNC ; Or resync bit on.
stosb ; Store it out into data stream.
Note msg1
loop @@SQU ; Go check squelching.
jmp @@DONE ; Done, if this was last data sample.
@@BCMP: mov bx,[BEST1] ; Get best comp.
mov ax,[BEST2] ; Get best bit size.
mov bh,al ; Into BH
mov ax,32000
push ax
push [PREV] ; Pass prev.
call ComputeError ; Re-compute error term.
add sp,4
mov [PREV],ax ; New previous.
;; Now time to store results!
mov bx,[BEST1] ; Get best comp.
cmp [BEST2],1 ; 1 bit?
jne @@NXT1
call Fold1Bit ; Fold 1 bit data.
Note msg2
jmp short @@IN ; Reenter.
@@NXT1: cmp [BEST2],2 ; 2 bit data?
jne @@NXT2
call Fold2Bit
Note msg3
jmp short @@IN
@@NXT2:
call Fold4Bit
Note msg4
@@IN: mov ax,[FRAME]
pop cx ; Get back CX
add si,ax ; Advance source
sub cx,ax ; Decrement data count.
jnz @@SQU ; Continue, if not at end.
@@DONE:
mov ax,di ; Size of compressed file.
les di,[DHAN]
sub ax,di ; Difference.
@@EXIT:
PopCREGS
PLEAVE
ret
endp
;; Compute error:
;; Registers on entry are:
;; DS:SI -> source data.
;; CX -> number of bytes to compute error term in.
;; DX -> total error incurred.
;; BL -> delta comp size.
;; BH -> maximum bit size value, positive or negative.
;; Exit: CX,DS:SI stay the same.
;; DX -> total error term.
;; AX -> new previous.
Proc ComputeError near
ARG PREV:WORD,MINERR:WORD
LOCAL CUR:WORD = LocalSpace
PENTER LocalSpace
push cx
push si
push di ; Save destination address.
xor dx,dx ; Initally no error.
@@CERR: lodsb ; Get a data byte.
xor ah,ah ; Zero high byte.
mov [CUR],ax ; Save as current sample.
sub ax,[PREV]
cmp bl,1
je @@ND
idiv bl ; Divided by delta mod size.
@@ND: or al,al
js @@DON ; Do negative side.
jnz @@CNT ; If not zero then continue.
inc al ; Can't represent a zero, make it one.
@@CNT: cmp al,bh ; > max representative size?
jle @@OK ; no, it fit as is.
mov al,bh ; Make it the max representative size.
jmp short @@OK ;
@@DON: neg al ; Make it positive.
cmp al,bh ; > max representative size?
jbe @@K2 ; no, use it.
mov al,bh ; Make it the max representative size.
@@K2: neg al ; Make it negative again.
@@OK:
stosb ; Store data value out.
imul bl ; Times delta comp value.
add ax,[PREV] ; Add to previous data point.
js @@CS ; Do signed case.
cmp ax,255 ; Did it over flow?
jle @@K3 ; No, then it fit byte sized.
mov ax,255 ; Make it byte sized.
jmp short @@K3 ; Re-enter
@@CS: xor ax,ax ; Close as we can get, underflow.
@@K3: mov [PREV],ax ; This is our new aproximated value.
sub ax,[CUR] ; Less actual value.
jns @@K4 ; if positive then fine.
neg ax ; Take absolute value.
@@K4: add dx,ax ; Add into total error.
cmp dx,[MINERR] ; Greater than minimum error allowed?
jg @@OUT
loop @@CERR
@@OUT: mov ax,[PREV] ; Current previous data point.
pop di ; Restore destination address.
pop si ; Reset SI back to start.
pop cx ; Reset CX back to start.
PLEAVE
ret
endp
Macro BuildByte
LOCAL @@HOP1,@@HOP2
lodsb
or al,al ; Is it signed?
jns @@HOP1
shl ah,1 ; Rotate.
jmp short @@HOP2
@@HOP1: stc
rcl ah,1
@@HOP2:
endm
;; Fold 1 bit data.
;; ES:DI -> points to data ready to fold out.
;; CX-> frame size.
;; BL-> contains delta size.
Proc Fold1Bit near
push ds
push si
push di ; Header byte address.
push es
pop ds ; DS=ES
mov si,di ; Source and dest.
inc di ; skip past header byte.
@@FOLD: xor ah,ah ; Dest byte to be built, zero it.
BuildByte
BuildByte
BuildByte
BuildByte
BuildByte
BuildByte
BuildByte
BuildByte
mov al,ah
stosb ; Store it out.
sub cx,8 ; Less the 8 samples just folded up.
jnz @@FOLD ; Continue.
pop si ; Get back header byte address.
mov al,bl ; Get delta comp size.
dec al ; Less one.
or al,ONEBIT ; Or the One Bit mode flag on.
mov [ds:si],al ; Store header byte.
pop si
pop ds
ret
endp
;; 2 Bit Format: 00 -> -2
;; 01 -> -1
;; 10 -> +1
;; 11 -> +2
Macro BByte
LOCAL @@HOP1,@@HOP2
lodsb
or al,al ; Is it signed?
jns @@HOP1
add al,2 ; Adjust it.
jmp short @@HOP2
@@HOP1: inc al ; Plus 1 to fit into format size.
@@HOP2: shl ah,1
shl ah,1
or ah,al ; Place bits into byte being built.
endm
;; Fold 2 bit data.
;; ES:DI -> points to data ready to fold out.
;; CX-> frame size.
;; BL-> contains delta size.
Proc Fold2Bit near
push ds
push si
@@F2:
push di ; Header byte address.
push es
pop ds ; DS=ES
mov si,di ; Source and dest.
inc di ; skip past header byte.
@@FOLD: xor ah,ah ; Dest byte to be built, zero it.
BByte
BByte
BByte
BByte
mov al,ah
stosb ; Store it out.
sub cx,4 ; Folded up 4 samples.
jnz @@FOLD ; Continue.
pop si ; Get back header byte address.
mov al,bl ; Get delta comp size.
dec al ; Less one.
or al,TWOBIT ; Or the One Bit mode flag on.
mov [ds:si],al ; Store header byte.
pop si
pop ds
ret
endp
;; Four bit format:
;; 0 -> -8
;; 1 -> -7
;; 2 -> -6
;; 3 -> -5
;; 4 -> -4
;; 5 -> -3
;; 6 -> -2
;; 7 -> -1
;; 8 -> +1
;; 9 -> +2
;;10 -> +3
;;11 -> +4
;;12 -> +5
;;13 -> +6
;;14 -> +7
;;15 -> +8
Macro Adjust4bit
LOCAL @@HOP1,@@HOP2
lodsb
or al,al
jns @@HOP1
add al,8 ; Adjust it.
jmp short @@HOP2
@@HOP1: add al,7 ; Adjust it.
@@HOP2:
endm
;; Fold 4 bit data.
;; ES:DI -> points to data ready to fold out.
;; CX-> frame size.
;; BL-> contains delta size.
Proc Fold4Bit near
push ds
push si
push di ; Header byte address.
push es
pop ds ; DS=ES
mov si,di ; Source and dest the same.
inc di ; skip past header byte.
@@FOLD: Adjust4bit ; Get first sample.
ShiftL al,4 ; Into high nibble.
mov ah,al ; Into AH
Adjust4bit ; Get next nibble.
or al,ah ; One whole byte.
stosb ; Store it out.
sub cx,2 ; Folded up 4 samples.
jnz @@FOLD ; Continue.
pop si ; Get back header byte address.
mov al,bl ; Get delta comp size.
dec al ; Less one.
or al,FOURBIT ; Or the One Bit mode flag on.
mov [ds:si],al ; Store header byte.
pop si
pop ds
ret
endp
msg0 db "SQUELCH"
msg1 db "RESYNC "
msg2 db "1 BIT "
msg3 db "2 BIT "
msg4 db "4 BIT "
Proc Notify near
ARG MSG:WORD
PENTER 0
PushAll
push cs
pop ds
mov ax,0B800h
mov es,ax
mov si,[MSG]
xor di,di
mov ah,1Fh
mov cx,7
@@SND: lodsb
stosw
loop @@SND
PopAll
PLEAVE
ret
endp
ENDS
END